import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { NulResponse, createEmptyRequest, createRequest } from "./common";
import { RootState } from "./store";
import { cloneArray } from "../util/Arrays";
import { getRequest } from "../util/Auth";

interface SupplierEntry {
  id: number;
  name: string;
  contact: string;
  phone: string;
  email: string;
  address: string;
}

interface SupplierState {
  fetched: boolean;
  entries: SupplierEntry[];
}

interface SupplierRequest {
  name: string;
  contact: string;
  phone: string;
  email: string;
  address: string;
}

interface CreateSupplierResponse {
  id: number;
}

interface SupplierDeleteRequest {
  id: number[];
}

const supplierInitialState: SupplierState = {
  fetched: false,
  entries: []
};

export const fetchAllSupplierEntries = createAsyncThunk('api/fetchAllSupplierEntries', async (_: void, { getState, rejectWithValue }) => {
  const state = getState() as RootState;
  try {
    const request = getRequest(state);
    const response = await request.post<NulResponse<SupplierEntry[]>>('/service/supplier/fetchAll',
      createEmptyRequest());
    return response.data;
  }
  catch (e) {
    return rejectWithValue(e);
  }
});

export const createNewSupplier = createAsyncThunk('api/createNewSupplier', async (supplier: SupplierRequest, { getState, rejectWithValue }) => {
  const state = getState() as RootState;
  try {
    const request = getRequest(state);
    const response = await request.post<NulResponse<CreateSupplierResponse>>('/service/supplier/createEntry',
      createRequest(supplier));
    return response.data;
  }
  catch (e) {
    return rejectWithValue(e);
  }
});

export const modifySupplier = createAsyncThunk('api/modifySupplier', async (supplier: SupplierEntry, { getState, rejectWithValue }) => {
  const state = getState() as RootState;
  try {
    const request = getRequest(state);
    const response = await request.post<NulResponse<null>>('/service/supplier/modifyEntry',
      createRequest(supplier));
    return response.data;
  }
  catch (e) {
    return rejectWithValue(e);
  }
});

export const deleteSupplier = createAsyncThunk('api/deleteSupplier', async (id: number[], { getState, rejectWithValue }) => {
  const state = getState() as RootState;
  try {
    const request = getRequest(state);
    const response = await request.post<NulResponse<null>>('/service/supplier/deleteEntry',
      createRequest<SupplierDeleteRequest>({ id }));
    return response.data;
  }
  catch (e) {
    return rejectWithValue(e);
  }
});

const supplierSlice = createSlice({
  name: 'supplier',
  initialState: supplierInitialState,
  reducers: {

  },
  extraReducers: (builder) => {
    builder.addCase(fetchAllSupplierEntries.rejected, (state, action) => {
      console.error(action.error);
    }).addCase(fetchAllSupplierEntries.fulfilled, (state, action) => {
      state.fetched = true;
      state.entries = action.payload.result;
    }).addCase(createNewSupplier.fulfilled, (state, action) => {
      console.log(action.payload);
      const entry: SupplierEntry = {
        ...action.meta.arg,
        ...action.payload.result
      };
      state.entries.push(entry);
      state.entries.sort((a, b) => a.id - b.id);
    }).addCase(createNewSupplier.rejected, (state, action) => {
      console.error(action.error);
    }).addCase(modifySupplier.fulfilled, (state, action) => {
      const index: number = state.entries.findIndex(item => item.id === action.meta.arg.id);
      if (index !== -1) {
        state.entries[index] = action.meta.arg;
      }
    }).addCase(modifySupplier.rejected, (state, action) => {
      console.error(action.error);
    }).addCase(deleteSupplier.fulfilled, (state, action) => {
      const deletedIds: number[] = cloneArray(action.meta.arg);
      const supplierEntries: SupplierEntry[] = state.entries;
      deletedIds.sort();
      const result: SupplierEntry[] = [];
      for (let i = 0, j = 0; j < supplierEntries.length; ++j) {
        if (supplierEntries[j].id !== deletedIds[i])
          result.push(supplierEntries[j]);
        else ++i;
      }
      state.entries = result;
    }).addCase(deleteSupplier.rejected, (state, action) => {
      console.error(action.error);
    });
  }
});

export type { SupplierEntry };
export const { actions } = supplierSlice;
export const selectSupplierEntries = (state: RootState) => state.supplierInformationReducer.entries;
export const selectSupplierFetched = (state: RootState) => state.supplierInformationReducer.fetched;
export default supplierSlice.reducer;